package route

import (
	"encoding/json"
	"ia/apps/admin/middleware"
	"ia/apps/admin/web/dts/sout"
	"ia/common/model"
	"ia/common/model/modeladmin"
	"ia/common/support"
	"ia/common/support/define"
	"strings"
	"time"

	"github.com/arl/statsviz"
	"github.com/iris-contrib/middleware/cors"
	"github.com/kataras/iris/v12"
	"github.com/kataras/iris/v12/middleware/rate"
)

func setup(app *iris.Application) (api iris.Party) {
	app.SetExecutionRules(iris.ExecutionRules{
		Done: iris.ExecutionOptions{Force: true},
	})
	app.UseGlobal(func(ctx iris.Context) {
		ctx.Values().Set("st", time.Now().UnixMicro())
		ctx.Next()
	})
	app.DoneGlobal(done)

	iris.RegisterOnInterrupt(GLogSink.Flush)

	// monitor
	statsvizPath := "/statsviz/"
	serveRoot := statsviz.IndexAtRoot(statsvizPath)
	serveWS := statsviz.NewWsHandler(time.Second * 6)
	app.UseRouter(func(ctx iris.Context) {
		if strings.HasPrefix(ctx.Path(), statsvizPath+"ws") {
			serveWS(ctx.ResponseWriter(), ctx.Request())
		} else if strings.HasPrefix(ctx.Path(), statsvizPath) {
			serveRoot(ctx.ResponseWriter(), ctx.Request())
		} else {
			ctx.Next()
		}
	})

	// 错误处理
	app.OnAnyErrorCode(func(ctx iris.Context) {
		var code define.Code
		switch ctx.GetStatusCode() {
		case iris.StatusNotFound:
			code = define.CodeNotFount
		default:
			code = define.CodeFailure
		}
		support.Error_(ctx, ctx.GetStatusCode(), code, "服务器错误：%v", ctx.GetErr())
	})

	crs := cors.New(cors.Options{
		AllowedOrigins: []string{"*"},
		AllowedHeaders: []string{"*"},
		AllowedMethods: []string{"GET", "POST", "PUT", "DELETE", "OPTIONS"},
		//Debug:            true,
	})
	app.UseRouter(crs)

	api = app.Party("/api/admin")

	// 每秒可以1个请求,最大并发5. 每分钟检查,超过5分钟的移除掉
	limit := rate.Limit(1, 5, rate.PurgeEvery(time.Minute, 5*time.Minute))
	api.Use(limit)
	api.Use(middleware.ServeHTTP)
	return api
}

func done(ctx iris.Context) {
	for _, v := range sout.GPolicyLogList {
		if v.V2 == ctx.Path() && v.V3 == ctx.Method() {
			st := ctx.Values().GetInt64Default("st", 0)
			diff := time.Since(time.UnixMicro(st)).Milliseconds() // 毫秒 1/1000s

			params, _ := json.Marshal(ctx.URLParams())
			body, _ := ctx.GetBody()

			var groupName, name string
			routeStr := strings.Split(ctx.GetCurrentRoute().String(), " ")
			if len(routeStr) > 0 {
				title := routeStr[0]
				arr := strings.Split(title, "~")
				if len(arr) >= 2 {
					groupName = arr[0]
					name = arr[1]
				}
			}

			userAgent := ctx.Request().UserAgent()
			var userAgent2 string = "未知"
			if strings.Contains(userAgent, "Chrome") {
				userAgent2 = "Chrome"
			}
			if strings.Contains(userAgent, "Firefox") {
				userAgent2 = "Firefox"
			}
			GLogSink.Append(&modeladmin.AdminLog{
				Model: model.Model{
					CreatorId: ctx.Values().GetInt64Default(define.Uid, 0),
				},
				IpAddr:         ctx.RemoteAddr(),
				City:           ctx.RemoteAddr(),
				Os:             strings.Replace(ctx.Request().Header.Get("Sec-Ch-Ua-Platform"), "\"", "", -1),
				UserAgent:      userAgent2,
				Path:           ctx.Path(),
				Method:         ctx.Method(),
				Params:         string(params),
				Data:           string(body),
				GroupName:      groupName,
				Name:           name,
				Duration:       int(diff),
				RespStatusCode: ctx.ResponseWriter().StatusCode(),
			})
		}
	}
}

func buildIfaceList(app *iris.Application) {
	list := make([]*sout.AdminRoutesOut, 0)
	for _, v := range app.GetRoutes() {
		split := strings.Split(v.Title, "~")
		if len(split) == 3 {
			if v.Method == "GET" || v.Method == "POST" || v.Method == "DELETE" || v.Method == "PUT" {
				list = append(list, &sout.AdminRoutesOut{
					Path:      v.Path,
					Method:    v.Method,
					Suf:       ".*",
					Tenant:    define.GConfig.App.Own.Tenant,
					GroupName: split[0],
					Name:      split[1],
					Memo:      split[2],
				})
			}
		}
	}
	sout.GIfaceList = list

	// andtv的select group用
	// counter := 1
	// i := 0
	// var j int
	// for {
	// 	if i >= len(list) {
	// 		break
	// 	}
	// 	for j = i + 1; j < len(list) && list[i].GroupName == list[j].GroupName; j++ {
	// 	}

	// 	options := make([]any, 0)
	// 	for _, v := range list[i:j] {
	// 		options = append(options, iris.Map{
	// 			"key":   counter,
	// 			"value": v.Path,
	// 			"label": v.Name,
	// 		})
	// 		counter++
	// 	}
	// 	pout.GIfaceList = append(pout.GIfaceList, iris.Map{
	// 		"key":     counter,
	// 		"label":   list[i].GroupName,
	// 		"options": options,
	// 	})
	// 	i = j
	// 	counter++
	// }
}
